//------------------------------------------------------------------------------
//!	@file	dda.c
//!	@brief
//!		Digital Differential Analyzer
//!
//!	@Description
//!		This is a lift of an algorithm from a Bruce Artwick book on
//!		graphics displays.
//!
//!
//!	Originally Developed: July, 1997 to October, 1999
//!
//!	$Id: dda.c 158 2013-03-03 07:00:15Z ac.verbeck@gmail.com $
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//	Copyright and Disclaimer Notice
//
//	Copyright (c) 2013 A.C. Verbeck
//
//	This file is part of CreateLUT: A LUT creation library.
//
//	CreateLUT is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	CreateLUT is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with CreateLUT.  If not, see <http://www.gnu.org/licenses/>.
//
//------------------------------------------------------------------------------

#include <stdlib.h>
#include <math.h>

#include <stdint.h>
#include <stdbool.h>

#include "dda.h"
#include "SysParam.h"

static	int32_t	dx,dy,err;
static	void	Octant1(uint8_t* OutArr, int32_t x1, int32_t y1);
static	void	Octant2(uint8_t* OutArr, int32_t x1, int32_t y1);
static	void	Octant7(uint8_t* OutArr, int32_t x1, int32_t y1);
static	void	Octant8(uint8_t* OutArr, int32_t x1, int32_t y1);

//
//	Name:
//		dda
//
//	Description:
//		Draws a line in the OutArr using the points specified
//
//	Parameters:
//		OutArr[]:	Output array
//		int32_t	x1:		Start X
//		int32_t	y1:		Start Y
//		int32_t	x2:		End X
//		int32_t	y2:		End Y
//
//	Returns:
//		(No direct return)
//		Indirect: The OutArr[] array is updated.
//
void dda(uint8_t* OutArr, int32_t x1, int32_t y1, int32_t x2, int32_t y2)
{
	int32_t	tx,ty;

//
//	Flip if line "backward"
//
	if (x2 < x1) {
		tx = x2;
		ty = y2;
		x2 = x1;
		y2 = y1;
		x1 = tx;
		y1 = ty;
	}

//
//	Initialize local variables
//
	dx  = x2-x1;
	dy  = y2-y1;
	err = 0;

//
//	Determine octant and jump
//
	if (dy < 0)
		if (-dy > dx)	Octant7(OutArr, x1, y1);
		else			Octant8(OutArr, x1, y1);
	else if (dy > dx)	Octant2(OutArr, x1, y1);
	else			Octant1(OutArr, x1, y1);
}

//
//	Name:
//		Octant1
//
//	Description:
//
//	Parameters:
//		OutArr[]:	Output array
//		int32_t	x1:		Start X
//		int32_t	y1:		Start Y
//
//	Returns:
//		(No direct return)
//		Indirect: The OutArr[CURVE_SZ] array is updated.
//
static void Octant1(uint8_t* OutArr, int32_t x1, int32_t y1)
{
	int32_t i;
	err = -dx/2;

	for (i=0; i<=dx; i++) {					// Rise is greater than run
		OutArr[x1++] = (uint8_t)y1;			// Set the point
		err += dy;							// Boost the error
		if (err >= 0) {						// If the error has overflowed...
			y1++;							// Move up one point
			err-=dx;						// Subtract out the error
		}
	}
}

//
//	Name:
//		Octant2
//
//	Description:
//
//	Parameters:
//		OutArr[]:	Output array
//		int32_t	x1:		Start X
//		int32_t	y1:		Start Y
//
//	Returns:
//		(No direct return)
//		Indirect: The OutArr[CURVE_SZ] array is updated.
//
static void Octant2(uint8_t* OutArr, int32_t x1, int32_t y1)
{
	int32_t i;
	err = -dy/2;

	for (i=0; i<=dy; i++) {					// Rise is greater than run
		OutArr[x1] = (uint8_t)y1++;			// Set the point
		err += dx;							// Boost the error
		if (err >= 0) {						// If the error has overflowed...
			x1++;							// Move up one point
			err-=dy;						// Subtract out the error
		}
	}
}

//
//	Name:
//		Octant7
//
//	Description:
//
//	Parameters:
//		OutArr[CURVE_SZ]:	Output array
//		int32_t	x1:				Start X
//		int32_t	y1:				Start Y
//
//	Returns:
//		(No direct return)
//		Indirect: The OutArr[CURVE_SZ] array is updated.
//
static void Octant7(uint8_t* OutArr, int32_t x1, int32_t y1)
{
	int32_t i;
	err = dy/2;

	for (i=0; i<=dy; i++) {					// Rise is greater than run
		OutArr[x1] = (uint8_t)y1--;			// Set the point
		err += dx;							// Boost the error
		if (err >= 0) {						// If the error has overflowed...
			x1++;							// Move up one point
			err+=dy;						// Subtract out the error
		}
	}
}

//
//	Name:
//		Octant8
//
//	Description:
//
//	Parameters:
//		OutArr[]:	Output array
//		int32_t	x1:		Start X
//		int32_t	y1:		Start Y
//
//	Returns:
//		(No direct return)
//		Indirect: The OutArr[CURVE_SZ] array is updated.
//
static void Octant8(uint8_t* OutArr, int32_t x1, int32_t y1)
{
	int32_t i;
	err = -dx/2;

	for (i=0; i<=dx; i++) {					// Rise is greater than run
		OutArr[x1++] = (uint8_t)y1;			// Set the point
		err -= dy;							// Boost the error
		if (err >= 0) {						// If the error has overflowed...
			y1--;							// Move up one point
			err-=dx;						// Subtract out the error
		}
	}
}

//
//	End: dda.c
//